﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using ParticleSystem;
using Keys = Microsoft.Xna.Framework.Input.Keys;

namespace BGSpaceShooter
{
    public class GamePad
    {
        private TcpListener listener;
        private TcpClient client;

        private double[] accelerometerValues = new double[3] { 0, 0, 10 };
        private double[] gyroscopeValues = new double[3] { 0, 0, 0 };

        private Boolean isGyroscopeActive = false;
        private Boolean isFireButtonActive = false;
        private Boolean isAccButtonActive = false;
        private Boolean isLeftActive = false;
        private Boolean isRightActive = false;
        private Boolean isStoptActive = false;
        private Boolean stop = false;


        private object mutex = new object();
        private object buttonMutex = new object();

        private StarFighter player;

        public StarFighter Player
        {
            get { return player; }
            set
            {
                player = value;
                lastPlayerHp = player.HP;
            }
        }

        public int lastPlayerHp;


        public Boolean Stop
        {
            get
            {
                lock (this)
                {
                    return stop;
                }
            }
            set { lock (this) { stop = value; } }
        }

        public double[] AccelerometerValues
        {
            get
            {
                lock (mutex)
                {
                    return accelerometerValues;
                }
            }
        }

        public Vector3 GyroscopeValues
        {
            get
            {
                lock (mutex)
                {
                    return new Vector3((float)gyroscopeValues[0], (float)gyroscopeValues[1], (float)gyroscopeValues[2]);
                }
            }
        }

        public Boolean GyroscopeActive
        {
            get
            {
                lock (mutex)
                {
                    return isGyroscopeActive;
                }
            }
        }

        public Boolean FireButton
        {
            get
            {
                lock (buttonMutex)
                {
                    return isFireButtonActive;
                }
            }
        }

        public Boolean AccelerateButton
        {
            get
            {
                lock (buttonMutex)
                {
                    return isAccButtonActive;
                }
            }
        }

        public Boolean FreeLookButton
        {
            get
            {
                lock (buttonMutex)
                {
                    return isGyroscopeActive;
                }
            }
        }

        public Boolean LeftButton
        {
            get
            {
                lock (buttonMutex)
                {
                    return isLeftActive;
                }
            }
        }


        public Boolean RightButton
        {
            get
            {
                lock (buttonMutex)
                {
                    return isRightActive;
                }
            }
        }

        public Boolean StopButton
        {
            get
            {
                lock (buttonMutex)
                {
                    return isStoptActive;
                }
            }
        }


        public void DoAcceptTcpClientCallback(IAsyncResult ar)
        {
            TcpListener listener = (TcpListener)ar.AsyncState;
            client = listener.EndAcceptTcpClient(ar);
            new Thread(process).Start();
        }

        public void process()
        {

            byte[] buff = new byte[1024];
            byte[] wrbuff = new byte[1024];
            NetworkStream ns = client.GetStream();
            string lastMessage = "null";
            int k = 0;
            while (!Stop)
            {
                if (Player != null)
                {
                    String health = Player.HealthPercent.ToString();
                    health = health.Replace(',', '.');
                    wrbuff = System.Text.Encoding.UTF8.GetBytes("0," + health + "\n");
                    ns.Write(wrbuff, 0, wrbuff.Length);

                    if (Player.HP < lastPlayerHp)
                    {
                        wrbuff = System.Text.Encoding.UTF8.GetBytes("2\n");
                        ns.Write(wrbuff, 0, wrbuff.Length);
                    }
                    lastPlayerHp = Player.HP;


                }

                StringBuilder msg = new StringBuilder();
                do
                {
                    int numberOfReads = ns.Read(buff, 0, buff.Length);
                    if (numberOfReads > 1)
                    {
                        msg.Append(Encoding.UTF8.GetString(buff, 0, numberOfReads));
                    }
                    Thread.Sleep(50);
                } while (msg.Length < 1024);


                String val = msg.ToString();

                string[] ar = val.Split("\n".ToCharArray());

                string s = ar[ar.Length - 4];
                if (!lastMessage.Equals(s))
                {

                    lastMessage = s;
                    string[] values = s.Split(",".ToCharArray());



                    lock (mutex)
                    {

                        isGyroscopeActive = values[0].Equals("1");
                        isFireButtonActive = values[4].Equals("1");
                        isAccButtonActive = values[1].Equals("1");
                        isLeftActive = values[2].Equals("1");
                        isRightActive = values[3].Equals("1");
                        isStoptActive = values[5].Equals("1");


                        if (!isGyroscopeActive)
                        {
                            for (int i = 6; i < 9; i++)
                            {
                                accelerometerValues[i - 6] = double.Parse(values[i], NumberStyles.Any,
                                                                      CultureInfo.InvariantCulture);
                            }
                        }
                        else
                        {
                            for (int i = 6; i < 9; i++)
                            {
                                gyroscopeValues[i - 6] = double.Parse(values[i], NumberStyles.Any,
                                                                      CultureInfo.InvariantCulture);
                            }
                        }
                    }
                }


            }

        }

        public GamePad(string ip, int port)
        {
            listener = new TcpListener(IPAddress.Parse(ip), port);
            listener.Start();
            listener.BeginAcceptTcpClient(DoAcceptTcpClientCallback, listener);


        }

        public List<Keys> getKeyAndAxisState()
        {
            var keys = new List<Keys>();


            if (AccelerateButton)
            {
                keys.Add(Keys.W);
            }

            if (FireButton)
            {
                keys.Add(Keys.Space);
            }

            if (LeftButton)
            {
                keys.Add(Keys.Left);
            }

            if (RightButton)
            {
                keys.Add(Keys.Right);
            }

            if (StopButton)
            {
                keys.Add(Keys.S);
            }

            keys.AddRange(checkAndPress(AccelerometerValues[0], Keys.Down, Keys.Up, 0));
            keys.AddRange(checkAndPress(AccelerometerValues[1], Keys.A, Keys.D, 0));
            return keys;
        }

        private List<Keys> checkAndPress(double axis, Keys up, Keys down, double stableValue)
        {
            var keys = new List<Keys>();

            double delta = 2;
            if (Math.Abs(axis - stableValue) > delta)
            {
                if (axis > stableValue)
                {
                    keys.Add(up);
                }
                else
                {
                    keys.Add(down);
                }
            }
            return keys;
        }
    }
}